package fr.inria.phoenix.diasuite.framework.misc;

import fr.inria.diagen.core.deploy.AbstractDeploy;

import fr.inria.phoenix.diasuite.framework.context.alert.AbstractAlert;
import fr.inria.phoenix.diasuite.framework.context.answer.AbstractAnswer;
import fr.inria.phoenix.diasuite.framework.context.cookerprofile.AbstractCookerProfile;
import fr.inria.phoenix.diasuite.framework.context.cookerready.AbstractCookerReady;
import fr.inria.phoenix.diasuite.framework.context.cookerstatus.AbstractCookerStatus;
import fr.inria.phoenix.diasuite.framework.context.presence.AbstractPresence;

import fr.inria.phoenix.diasuite.framework.controller.answercontroller.AbstractAnswerController;
import fr.inria.phoenix.diasuite.framework.controller.promptercontroller.AbstractPrompterController;
import fr.inria.phoenix.diasuite.framework.controller.timercontroller.AbstractTimerController;

/**
 * This class should be implemented to bind the implementation of the various components
 */
public abstract class AppComponentBinder extends AbstractDeploy {

    // Context instances
    private AbstractAlert alertInstance = null;
    private AbstractAnswer answerInstance = null;
    private AbstractCookerProfile cookerProfileInstance = null;
    private AbstractCookerReady cookerReadyInstance = null;
    private AbstractCookerStatus cookerStatusInstance = null;
    private AbstractPresence presenceInstance = null;

    // Controller instances
    private AbstractAnswerController answerControllerInstance = null;
    private AbstractPrompterController prompterControllerInstance = null;
    private AbstractTimerController timerControllerInstance = null;
    
    @Override
    public void deployAll() {
        // Initialization of contexts
        if (alertInstance == null)
            alertInstance = getInstance(getAlertClass());
        if (answerInstance == null)
            answerInstance = getInstance(getAnswerClass());
        if (cookerProfileInstance == null)
            cookerProfileInstance = getInstance(getCookerProfileClass());
        if (cookerReadyInstance == null)
            cookerReadyInstance = getInstance(getCookerReadyClass());
        if (cookerStatusInstance == null)
            cookerStatusInstance = getInstance(getCookerStatusClass());
        if (presenceInstance == null)
            presenceInstance = getInstance(getPresenceClass());
        // Intialization of controllers
        if (answerControllerInstance == null)
            answerControllerInstance = getInstance(getAnswerControllerClass());
        if (prompterControllerInstance == null)
            prompterControllerInstance = getInstance(getPrompterControllerClass());
        if (timerControllerInstance == null)
            timerControllerInstance = getInstance(getTimerControllerClass());
        // Deploying contexts
        deploy(alertInstance);
        deploy(answerInstance);
        deploy(cookerProfileInstance);
        deploy(cookerReadyInstance);
        deploy(cookerStatusInstance);
        deploy(presenceInstance);
        // Deploying controllers
        deploy(answerControllerInstance);
        deploy(prompterControllerInstance);
        deploy(timerControllerInstance);
    }
    
    @Override
    public void undeployAll() {
        // Undeploying contexts
        undeploy(alertInstance);
        undeploy(answerInstance);
        undeploy(cookerProfileInstance);
        undeploy(cookerReadyInstance);
        undeploy(cookerStatusInstance);
        undeploy(presenceInstance);
        // Undeploying controllers
        undeploy(answerControllerInstance);
        undeploy(prompterControllerInstance);
        undeploy(timerControllerInstance);
    }
    
    // Abstract binding methods for contexts
    /**
     * Overrides this method to provide the implementation class of the <code>Alert</code> context
    
    <pre>
    context Alert as Boolean{
     * 	when provided tickMinute from Clock get Presence
     * 	maybe publish;
     * }
    </pre>
    @return a class object of a derivation of {@link AbstractAlert} that implements the <code>Alert</code> context
     */
    public abstract Class<? extends AbstractAlert> getAlertClass();
    
    /**
     * Overrides this method to provide the implementation class of the <code>Answer</code> context
    
    <pre>
    context Answer as Boolean{
     * 	when provided answer from Prompter
     * 	maybe publish;
     * }
    </pre>
    @return a class object of a derivation of {@link AbstractAnswer} that implements the <code>Answer</code> context
     */
    public abstract Class<? extends AbstractAnswer> getAnswerClass();
    
    /**
     * Overrides this method to provide the implementation class of the <code>CookerProfile</code> context
    
    <pre>
    context CookerProfile as Boolean{
     * 	when provided timerTriggered from Timer 
     * 	always publish;
     * }
    </pre>
    @return a class object of a derivation of {@link AbstractCookerProfile} that implements the <code>CookerProfile</code> context
     */
    public abstract Class<? extends AbstractCookerProfile> getCookerProfileClass();
    
    /**
     * Overrides this method to provide the implementation class of the <code>CookerReady</code> context
    
    <pre>
    context CookerReady as Boolean{
     * 	when provided status from Cooker 
     * 	get currentElectricConsumption from ElectricMeter
     * 	always publish;
     * }
    </pre>
    @return a class object of a derivation of {@link AbstractCookerReady} that implements the <code>CookerReady</code> context
     */
    public abstract Class<? extends AbstractCookerReady> getCookerReadyClass();
    
    /**
     * Overrides this method to provide the implementation class of the <code>CookerStatus</code> context
    
    <pre>
    context CookerStatus as CookerStatus{
     * 	when provided Alert get CookerReady
     * 	maybe publish;
     * }
    </pre>
    @return a class object of a derivation of {@link AbstractCookerStatus} that implements the <code>CookerStatus</code> context
     */
    public abstract Class<? extends AbstractCookerStatus> getCookerStatusClass();
    
    /**
     * Overrides this method to provide the implementation class of the <code>Presence</code> context
    
    <pre>
    context Presence as Boolean{
     * 	when provided motion from MotionDetector
     * 	always publish;
     * }
    </pre>
    @return a class object of a derivation of {@link AbstractPresence} that implements the <code>Presence</code> context
     */
    public abstract Class<? extends AbstractPresence> getPresenceClass();
    
    // End of abstract binding methods for contexts
    
    // Abstract binding methods for controllers
    /**
     * Overrides this method to provide the implementation class of the <code>AnswerController</code> controller
    
    <pre>
    controller AnswerController{
     * 	when provided Answer do Off on Cooker;
     * }
    </pre>
    @return a class object of a derivation of {@link AbstractAnswerController} that implements the <code>AnswerController</code> controller
     */
    public abstract Class<? extends AbstractAnswerController> getAnswerControllerClass();
    
    /**
     * Overrides this method to provide the implementation class of the <code>PrompterController</code> controller
    
    <pre>
    controller PrompterController {
     * 	when provided CookerStatus do AskQuestion on Prompter;
     * 	when provided CookerProfile do AskQuestion on Prompter;
     * }
    </pre>
    @return a class object of a derivation of {@link AbstractPrompterController} that implements the <code>PrompterController</code> controller
     */
    public abstract Class<? extends AbstractPrompterController> getPrompterControllerClass();
    
    /**
     * Overrides this method to provide the implementation class of the <code>TimerController</code> controller
    
    <pre>
    controller TimerController {
     * 	when provided CookerReady do ScheduleTimer on Timer;
     * }
    </pre>
    @return a class object of a derivation of {@link AbstractTimerController} that implements the <code>TimerController</code> controller
     */
    public abstract Class<? extends AbstractTimerController> getTimerControllerClass();
    
    // End of abstract binding methods for controllers
}
